/************************************************************************************************************************************************************
*                          DESENVOLVEDORES: Denis Tobias; Diogo Oliveira; Marcel M. Marum; Marcos F. Rachid; Rodrigo M. Botelho
*                                       ORIENTADOR e DESENVOLVEDOR: Prof.Dr. Eraldo Pereira Marinho
*
*                                                           Arquivo: symtab.c
*
************************************************************************************************************************************************************/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "tokens.h"
#include "symtab.h"
#include "keywords.h"

char symtape[TAPELENGHT];//string que simula o numero de caracteres do arquivo.
int symtape_next = 1;//variavel que guarda a posição do arquivo no symtape.
int symtab[ENTRIES][COLUMNS]; //array que guarda os simbolos usados na estrutura pascal
int typetab[ENTRIES][COLUMNS]; //array que guarda os simbolos type usados na estrutura pascal
int symtab_next = 0;//variavel que guarda o numero de entradas inseridas no symtab
int sttype_next = 0;//variavel auxiliar para inserir o tipo do referente ao simbolo
int type_next = 0;//variavel que guarda o numero de entradas inseridas no typetab
int i;//variavel auxiliar de repetição

//função que busca um simbolo cadastrado do pascal e retorna sua posição no symtab.
int symtab_search (char const *symbol, int levlex)
{
//  printf("%d\n",symtab_next);
  for(i = 0; i<symtab_next; i++)
    {
      if (strcmp (symbol, symtape + symtab[i][0]) == 0 && symtab[i][2] <= levlex && symtab[i][4] == 0)
	return i;
    }
  return -1;
}

//função que insere o simbolo cadastro do pascal no symtab.
int symtab_insert (char *symbol, int levlex)
{
//  printf("%s %s\n",symbol,symtab[symtab_next][0]);
  if (symtab_next == ENTRIES){//verifica se o numero de entradas chegou ao limite.
    printf("Line %d - ERROR: Symbol Table has reached maximum number of entries.\n", line);
    exit(-1);
  }
  if (symtape_next + strlen (symbol) + 1 >= TAPELENGHT){//verifica se o tamanho do arquivo chegou ao limite
    printf("Line %d - ERROR: Tape reached maximum lenght.\n", line);
    exit(-1);
  }
  if (symtab_search(symbol, levlex) < 0){//verifica se já existe este simbolo cadastrado no symtab
    strcpy (symtape + symtape_next, symbol);
    symtab[symtab_next][0] = symtape_next;
    symtab[symtab_next][1] = sttype_next;
    symtab[symtab_next][2] = levlex;
    symtab[symtab_next][4] = 0;
    symtape_next += strlen (symbol) + 1;
    symtab_next++;
    return symtape_next;
  }else{
    printf("Line %d - ERROR: %s is an already declared variable.\n", line, symbol);
    exit(-1);
  }
}

//função que busca um simbolo cadastrado do pascal e retorna o tipo do simbolo em questão.
int sttype_search (char const *symbol, int levlex)
{
//  printf("%d\n",symtab_next);
  for(i = 0; i<symtab_next; i++)
    {
      //printf("%s, %s\n",symbol , symtape + symtab[i][0]);
      if (strcmp (symbol, symtape + symtab[i][0]) == 0 && symtab[i][2] <= levlex && symtab[i][4] == 0)
        return symtab[i][1];
    }
  printf("Line %d - ERROR: %s is an undeclared variable.\n", line, symbol);
  exit(-1);
  return -1;
}

//função que atualiza o tipo do simbolo e insere o seu offset.
int sttype_insert (int tpexpected, int lexlevel, int offset, int stringsize, int arraysize)
{
   int first = 1;
   int extravar = 0;
   switch(tpexpected){//tratamento para arrays
	case INTEGER:if(lexlevel == 0)
		     	extravar=32*arraysize;
		     break;
	case REAL:if(lexlevel == 0)
		  	extravar=64*arraysize;
		  break;
        case DOUBLE:if(lexlevel == 0)
		    	extravar=64*arraysize;
		    break;
	case STRING:if(lexlevel == 0)
			extravar=8*stringsize*arraysize;
		    break;
	case CHAR:if(lexlevel == 0)
		  	extravar=8*arraysize;
			   break;
	default:if(lexlevel == 0)
			extravar=1*arraysize;
   }
   for(i = 0; i<symtab_next; i++)
   {
//	printf("%d, %d, %d, %d\n", symtab[i][1], sttype_next, tpexpected, offset);
	if(symtab[i][1] == sttype_next){
		symtab[i][1] = tpexpected;
		if(!first){
			offset+=extravar;
			symtab[i][3] = offset;
		}else{
			symtab[i][3] = offset;
			first = 0;
		}
	}
   }
   sttype_next++;
   return offset;
}

//insere um simbolo de TYPE e o tipo que ele referencia.
int type_insert (char *symbol, int type, int arraysize, int levlex)
{
//  printf("%s %s\n",symbol,symtab[symtab_next][0]);
  if (symtab_next == ENTRIES){
    printf("Line %d - ERROR: Symbol Table has reached maximum number of entries.\n", line);
    exit(-1);
  }
  if (symtape_next + strlen (symbol) + 1 >= TAPELENGHT){
    printf("Line %d - ERROR: Tape reached maximum lenght.\n", line);
    exit(-1);
  }
  if (type_search(symbol, levlex) < 0){
    strcpy (symtape + symtape_next, symbol);
    typetab[type_next][0] = symtape_next;
    typetab[type_next][1] = type;
    typetab[type_next][2] = arraysize;
    typetab[type_next][3] = levlex;
    typetab[type_next][4] = 0;
    symtape_next += strlen (symbol) + 1;
    type_next++;
    return type_next;
  }else{
    printf("Line %d - ERROR: %s is an already declared type variable.\n", line, symbol);
    exit(-1);
  }
}

//função que busca um simbolo TYPE cadastrado do pascal e retorna sua posição no symtape.
int type_search (char const *symbol, int levlex)
{
  for(i = 0; i<type_next; i++)
    {
      if (strcmp (symbol, symtape + typetab[i][0]) == 0 && typetab[i][3] <= levlex && typetab[i][4] == 0)
        return typetab[i][0];
    }
  return -1;
}

//função que busca um simbolo TYPE cadastrado do pascal e retorna o tipo que ele representa.
int type_type_search (char const *symbol, int levlex)
{
  for(i = 0; i<type_next; i++)
    {
      if (strcmp (symbol, symtape + typetab[i][0]) == 0 && typetab[i][3] <= levlex && typetab[i][4] == 0){
//	printf("%d\n", typetab[i][1]);
        return typetab[i][1];
      }
    }
  printf("Line %d - ERROR: %s is an undeclared type variable.\n", line, symbol);
  exit(-1);
  return -1;
}

//função que busca um simbolo TYPE cadastrado do pascal e retorna o tamanho do array cadastrado.
int type_array_search (char const *symbol, int levlex)
{
  for(i = 0; i<type_next; i++)
    {
      if (strcmp (symbol, symtape + typetab[i][0]) == 0 && typetab[i][3] <= levlex && typetab[i][4] == 0){
//	printf("%d\n", typetab[i][2]);
        return typetab[i][2];
      }
    }
  printf("Line %d - ERROR: %s is an undeclared type variable.\n", line, symbol);
  exit(-1);
  return -1;
}

//função que seta como localvar os simbolos de nivel lexico >= 1 
void localvardelete (int levlex)
{
  for(i = 0; i<symtab_next; i++)
    {
      if (symtab[i][2] == levlex){
//      printf("%d\n", typetab[i][2]);
        symtab[i][4] = 1;
      }
    }
  for(i = 0; i<type_next; i++)
    {
      if(typetab[i][3] == levlex)
	typetab[i][4] = 1;
    }
}

//função em que mostra a tabela completa do symtab.
void printsymtab(void){
        printf("\n\n  symbol    |    type    |    levellex    |    offset    |    localvalue\n");
        for(i = 0; i<symtab_next; i++)
	{
                printf("  %s       |     %d     |       %d        |      %d    |          %d \n", symtape + symtab[i][0], symtab[i][1], symtab[i][2], symtab[i][3], symtab[i][4]);
        }
}

//função em que mostra a tabela completa do typetab.
void printtypetab(void){
        printf("\n\n  symbol    |    type    |    arraysize    |    levellex    |    localvalue\n");
        for(i = 0; i<type_next; i++)
        {
                printf("  %s       |     %d     |       %d     |        %d    |          %d\n", symtape + typetab[i][0], typetab[i][1], typetab[i][2], typetab[i][3], typetab[i][4]);
        }
	printf("\n\n");
}

